await 也需要 catch
· 阅读需 4 分钟
总把外行当内行,遇见问题总抓狂
不记得在哪里看了这么一句话:“在 js 中尽量不写 try...catch
,因为会拖累进程,甚至拖垮程序。每一个 try..catch
都将创建一个独立的内存,需要先执行一遍,然后看一下有没有错误,没有错误再返回源执行栈事件进行执行。“
当时,看见这句话,若获珍宝。巴不得在自己的项目中可以一个 try...catch
没有,也不能造成性能不足。
直到,昨晚一个小时一点点的打印找关于 triggerUncaughtException
的错,才发现,这真是“外行看热闹,内行看门道。半瓶子看自以为是和瞎几把信外行的瞎几把说”。
性能关键结论
场景 | 性能影响 | 数据参考 (V8 引擎) |
---|---|---|
无异常的 try/catch | 几乎无损耗( <1% 差异) | 每秒执行 1 亿次无感知 |
高频抛出异常 | 显著下降(10~100 倍) | 每秒处理异常 ≤1 万次 |
嵌套 try/catch | 作用域管理有轻微损耗 | 单层 vs 五层损耗差约 5% |
正确性 >> 性能:牺牲 1% 性能换取健壮的错误处理是值得的。只有对性能极其敏感的核心模块(如游戏引擎、高频交易系统),才需要抠 try/catch 的细节。
引擎优化原理
- 无异常路径的「快速通道」 V8 会对未触发异常的 try 代码块做内联缓存优化(Inline Caching),跳过异常监控逻辑。 类似 if/else 的预测执行机制,不影响主线程性能。
- 仅当 throw 时触发「慢速路径」 异常对象需要生成堆栈跟踪(Stack Trace),消耗 CPU。 垃圾回收压力增大(频繁创建/销毁 Error 对象)。
极端场景性能陷阱
- 高频异常抛出(灾难级性能)
// ❌ 错误用法:将异常用于正常控制流
function validate(num) {
try {
if (num < 0) throw new Error('Negative');
return num;
} catch (e) {
return 0;
}
}
// ✅ 优化方案:用条件判断代替异常
function validate(num) {
return num < 0 ? 0 : num;
}
性能对比:改用条件判断后,速度提升 50~100 倍。2. 热代码路径中的冗余 try/catch
// ❌ 不必要的 try/catch 包裹循环
try {
for (let i = 0; i < 1e6; i++) {
// 高频执行代码
}
} catch (e) {}
// ✅ 将 try/catch 移出循环
for (let i = 0; i < 1e6; i++) {
try {
/* 单次操作 */
} catch (e) {}
}
性能对比:外层包裹导致引擎无法优化,速度下降 5~10%。
建议
- 必要错误处理:对数据库、网络请求、文件 IO 等异步操作必须用 try/catch。
- 避免异常滥用:不要用 throw 替代条件判断(如参数校验)。
- 全局兜底:用 process.on('unhandledRejection') 或 window.onerror 捕获漏网之鱼。
- 性能敏感场景:对高频执行的数学计算、排序算法等,优先用 if 防御而非 try。